package com.hydra.framework.event.kvo.list;

import com.hydra.framework.event.kvo.KvoSource;
import com.hydra.framework.event.kvo.list.KvoListHelper.NSRange;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;

/**
 * Created by Hydra.
 *
 * 实现RandomAccess的接口会快一些，但是有一些疑虑，因为wrapped list不一定是RandomAccess的, 不过通常大部分情况是ArrayList的就没关系
 */
public class KvoList<T> implements List<T>, RandomAccess {

    private List<T> mList;

    private final KvoSource mSource;

    private final String mName;

    public KvoList(KvoSource source, String name) {
        this(source, name, null);
    }

    /**
     * @param list 默认是ArrayList，不会对传入的list做深拷贝
     */
    public KvoList(KvoSource source, String name, List<T> list) {
        mSource = source;
        mName = name;

        setWrappedList(list == null ? new ArrayList<T>() : list);
    }

    /**
     * 不会对传入的list做深拷贝，考虑到wrapped list可能会用不同类型的list
     */
    public void setWrappedList(List<T> list) {
        mList = list;

        KvoListHelper.notifyDataSetChanged(mSource, mName, mList);
    }

    public List<T> getWrappedList() {
        return mList;
    }

    @Override
    public void add(int location, T object) {
        mList.add(location, object);

        KvoListHelper.insert(mSource, mName, mList, location, 1);
    }

    @Override
    public boolean add(T object) {
        int oldSize = size();

        boolean result = mList.add(object);

        KvoListHelper.insert(mSource, mName, mList, oldSize, 1);

        return result;
    }

    @Override
    public boolean addAll(int location, Collection<? extends T> collection) {
        boolean result = mList.addAll(location, collection);

        KvoListHelper.insert(mSource, mName, mList, location, collection.size());

        return result;
    }

    @Override
    public boolean addAll(Collection<? extends T> collection) {
        int oldSize = size();

        boolean result = mList.addAll(collection);

        KvoListHelper.insert(mSource, mName, mList, oldSize, collection.size());

        return result;
    }

    @Override
    public void clear() {
        int preSize = size();

        mList.clear();

        KvoListHelper.rangeRemove(mSource, mName, mList, 0, preSize);
    }

    @Override
    public T remove(int location) {
        T t = mList.remove(location);

        KvoListHelper.rangeRemove(mSource, mName, mList, location, 1);

        return t;
    }

    @Override
    public boolean remove(Object object) {
        int index = mList.indexOf(object);

        if(index >= 0) {
            mList.remove(index);

            KvoListHelper.rangeRemove(mSource, mName, mList, index, 1);
        }

        return index >= 0;
    }

    /**
     * 调用者自己判断index范围
     */
    public void removeRange(int fromIndex, int toIndex) {
        subList(fromIndex, toIndex).clear();

        KvoListHelper.rangeRemove(mSource, mName, mList, fromIndex, toIndex - fromIndex);
    }

    /**
     * 调用者自己判断index范围
     * 非原子操作
     */
    public void rangeReplace(int fromIndex, int toIndex, List<T> srcList) {
        if(toIndex - fromIndex == srcList.size()) {
            mList.subList(fromIndex, toIndex).clear();
            mList.addAll(fromIndex, srcList);

            KvoListHelper.rangeReplace(mSource, mName, mList, fromIndex, toIndex);
        }
    }

    @Override
    public T set(int location, T object) {
        T t = mList.set(location, object);

        KvoListHelper.rangeReplace(mSource, mName, mList, location, 1);

        return t;
    }

    /**
     * 这里虽然是用ite做依次删除，但是做了个批量通知
     */
    @Override
    public boolean removeAll(Collection<?> collection) {
        boolean result = false;

        Iterator<?> it = iterator();

        NSRange currentRange = null;
        int i = 0;
        int currentDeleteLength = 0;

        while (it.hasNext()) {
            if (collection.contains(it.next())) {
                it.remove();

                if(currentRange == null) {
                    currentRange = new NSRange(i, 1);
                } else {
                    if(i == currentRange.location + currentRange.length) {
                        currentRange.length++;
                    } else {
                        KvoListHelper.rangeRemove(mSource, mName, mList, currentRange.location - currentDeleteLength, currentRange.length);

                        currentDeleteLength += currentRange.length;

                        currentRange = new NSRange(i, 1);
                    }
                }

                result = true;
            }

            i++;
        }

        if(currentRange != null) {
            KvoListHelper.rangeRemove(mSource, mName, mList, currentRange.location - currentDeleteLength, currentRange.length);
        }

        return result;
    }

    @Override
    public boolean retainAll(Collection<?> collection) {
        boolean result = false;

        Iterator<?> it = iterator();

        NSRange currentRange = null;
        int i = 0;
        int currentDeleteLength = 0;

        while (it.hasNext()) {
            if (!collection.contains(it.next())) {
                it.remove();

                if(currentRange == null) {
                    currentRange = new NSRange(i, 1);
                } else {
                    if(i == currentRange.location + currentRange.length) {
                        currentRange.length++;
                    } else {
                        KvoListHelper.rangeRemove(mSource, mName, mList, currentRange.location - currentDeleteLength, currentRange.length);

                        currentDeleteLength += currentRange.length;

                        currentRange = new NSRange(i, 1);
                    }
                }

                result = true;
            }

            i++;
        }

        if(currentRange != null) {
            KvoListHelper.rangeRemove(mSource, mName, mList, currentRange.location - currentDeleteLength, currentRange.length);
        }

        return result;
    }

    /**
     * 调用者自己判断index范围
     * 非原子操作
     */
    public void move(int fromIndex, int toIndex) {
        if(fromIndex != toIndex) {
            T t = mList.remove(fromIndex);

            mList.add(toIndex, t);

            KvoListHelper.move(mSource, mName, mList, fromIndex, toIndex);
        }
    }

    @Override
    public List<T> subList(int start, int end) {
        return mList.subList(start, end);
    }

    @Override
    public int size() {
        return mList.size();
    }

    @Override
    public Object[] toArray() {
        return mList.toArray();
    }

    @Override
    public <E> E[] toArray(E[] array) {
        return mList.toArray(array);
    }

    @Override
    public boolean isEmpty() {
        return mList.isEmpty();
    }

    @Override
    public Iterator<T> iterator() {
        return new KvoListIterator<>(mSource, mName, mList);
    }

    @Override
    public int lastIndexOf(Object object) {
        return mList.lastIndexOf(object);
    }

    @Override
    public ListIterator<T> listIterator() {
        return new KvoListIterator<>(mSource, mName, mList);
    }

    @Override
    public ListIterator<T> listIterator(int location) {
        return new KvoListIterator<>(mSource, mName, mList, location);
    }

    @Override
    public boolean contains(Object object) {
        return mList.contains(object);
    }

    @Override
    public boolean containsAll(Collection<?> collection) {
        return mList.containsAll(collection);
    }

    @Override
    public T get(int location) {
        return mList.get(location);
    }

    @Override
    public int indexOf(Object object) {
        return mList.indexOf(object);
    }
}
